package com.basic.ui.view

import android.animation.Animator
import android.animation.Animator.AnimatorListener
import android.animation.ObjectAnimator
import android.content.Context
import android.graphics.Canvas
import android.graphics.Color
import android.util.AttributeSet
import android.util.TypedValue
import android.view.View
import android.view.animation.LinearInterpolator
import android.widget.FrameLayout
import androidx.appcompat.widget.AppCompatTextView
import androidx.core.view.children
import com.basic.ui.R
import com.basic.ui.resColor
import com.basic.ui.resPx
import com.basic.ui.view.DanmuGroupView.DanmuItem
import kotlin.random.Random

/**
 *  简单的弹幕view
 *  支持从左向右滚LTR，从左向右滚RTL，位置固定FIX 三种显示模式
 *  支持自定义设置 Danmu item view： setDanmuItemViewFactory， 有默认值
 *  create and set [DanmuItem] proper
 *  call [addDanmu] or [addDanmus] to add damu
 *  call [start] [pause] [stop]
 *
 * @author: Peter Liu
 * @date: 2023/7/28
 */
class DanmuGroupView @JvmOverloads constructor(
    context: Context, attrs: AttributeSet? = null
) : FrameLayout(context, attrs) {
    enum class Mode {
        LTR,//从左向右滚
        RTL,//从左向右滚
        FIX //位置固定
    }

    private val playingAnimators by lazy { HashMap<AnimatorListener, ObjectAnimator>() }

    private val danmuItems by lazy { mutableListOf<DanmuItem>() }

    private var isStarted = false
    private var isPaused = false
    private var consumedY = 0 //上一个绘制view的Y方向的底部坐标
    private var playedCount = 0 //记录滚动完了的数

    init {
        setWillNotDraw(false)
        clipChildren = false
        clipToPadding = false
    }

    var itemMargin: Int = 60 //Px

    var mode: Mode = Mode.RTL

    //滚动模式是否重复滚动
    var isRepeatPlay = true

    //设置第一个弹幕条目的在Y 方向的位置，后续弹幕从这个位置往下排。
    var firstItemY: Int = 0

    //设置同时显示的最大弹幕数
    var maxCount: Int = Int.MAX_VALUE

    private var itemFactory: ((danmuItem: DanmuItem) -> View)? =
        { danmuItem: DanmuItem ->
            Color.TRANSPARENT
            AppCompatTextView(this.context).apply {
                text = danmuItem.text
                val padding = R.dimen.dp_12.resPx()
                setPadding(padding, padding, padding, padding)
                setTextSize(
                    TypedValue.COMPLEX_UNIT_PX, R.dimen.sp_12.resPx().toFloat()
                )
                setTextColor(Color.WHITE)
                background = RectShape(R.color.black_50.resColor()).setCornerRadius(
                    R.dimen.dp_24.resPx().toFloat()
                ).getDrawable()
            }
        }

    fun addDanmu(danmuItem: DanmuItem) {
        danmuItems.add(danmuItem)
        addView(danmuItem)
    }

    fun addDanmus(danmuItems: List<DanmuItem>) {
        this.danmuItems.addAll(danmuItems)
        danmuItems.forEach {
            addView(it)
        }
    }

    //设置Danmu item view 的 factory
    fun setDanmuItemViewFactory(factory: (danmuItem: DanmuItem) -> View) {
        this.itemFactory = factory
    }

    private fun addView(danmuItem: DanmuItem) {
        if (itemFactory != null) {
            val view = itemFactory!!.invoke(danmuItem)
            addView(view, LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT)
        }
    }

    fun start() {
        isStarted = true
        if (isPaused) {
            isPaused = false
            playingAnimators.values.forEach {
                it.resume()
            }
        } else {
            invalidate()
        }
    }

    fun pause() {
        isPaused = true
        playingAnimators.values.forEach {
            it.pause()
        }
    }

    fun stop() {
        isStarted = false
        playingAnimators.values.toList().forEach {
            it.cancel()
        }
        playingAnimators.clear()
        danmuItems.clear()
        playedCount = 0
        consumedY = 0
        removeAllViews()
    }

    override fun setVisibility(visibility: Int) {
        if (visibility != View.VISIBLE) {
            playingAnimators.values.toList().forEach {
                it.cancel()
            }
            playingAnimators.clear()
        }
        super.setVisibility(visibility)
    }

    override fun onLayout(changed: Boolean, left: Int, top: Int, right: Int, bottom: Int) {
        val h = measuredHeight - paddingTop - paddingBottom
        children.forEachIndexed { index, view ->
            val danmuItem = danmuItems[index]
            if (danmuItem.y < 0) {
                if (consumedY == 0) {
                    consumedY = firstItemY
                }
                var nextY = consumedY + itemMargin
                val nextBottom = nextY + view.measuredHeight
                if (nextBottom > h) {
                    //从最上面重新开始
                    nextY = itemMargin
                }
                danmuItem.y = nextY
                consumedY = nextY + view.measuredHeight
                val childLeft: Int
                val childTop: Int
                when (mode) {
                    Mode.LTR -> {
                        childLeft = -view.measuredWidth
                        childTop = danmuItem.y
                    }

                    Mode.RTL -> {
                        childLeft = measuredWidth
                        childTop = danmuItem.y
                    }

                    else -> {
                        childLeft = danmuItem.fixX
                        childTop = danmuItem.fixY
                    }
                }
                view.layout(
                    childLeft,
                    childTop,
                    view.measuredWidth + childLeft,
                    childTop + view.measuredHeight
                )
                //todo 计算x避免重叠
            }
        }
    }

    override fun onDraw(canvas: Canvas?) {
        super.onDraw(canvas)
        if (mode == Mode.FIX) {
            return
        }
        if (isStarted) {
            children.forEachIndexed { index, view ->
                val danmuItem = danmuItems[index]
                if (!danmuItem.animePlayed) {
                    anim(danmuItem, view)
                } else if (isRepeatPlay && !danmuItem.isAnimating) {
                    anim(danmuItem, view)
                }
            }
        }
    }

    private fun anim(danmuItem: DanmuItem, danmuView: View) {
        danmuItem.isAnimating = true
        danmuItem.animePlayed = true

        val animatorListener = object : AnimatorListener {
            override fun onAnimationStart(animation: Animator) {
            }

            override fun onAnimationEnd(animation: Animator) {
                danmuItem.isAnimating = false
                playedCount++
                playingAnimators.remove(this)
                if (isRepeatPlay && playedCount == danmuItems.size) {
                    playedCount = 0
                    invalidate()
                }
            }

            override fun onAnimationCancel(animation: Animator) {
            }

            override fun onAnimationRepeat(animation: Animator) {
            }
        }
        if (mode == Mode.LTR) {
            val animator = ObjectAnimator.ofFloat(
                danmuView, "x", -danmuView.width.toFloat(), width.toFloat()
            ).setDuration(danmuItem.duration)
            animator.interpolator = LinearInterpolator()
            animator.addListener(animatorListener)
            animator.startDelay = danmuItem.startOffset
            animator.start()
            playingAnimators[animatorListener] = animator
        } else if (mode == Mode.RTL) {
            val animator = ObjectAnimator.ofFloat(
                danmuView, "x", width.toFloat(), -danmuView.width.toFloat()
            ).setDuration(danmuItem.duration)
            animator.interpolator = LinearInterpolator()
            animator.addListener(animatorListener)
            animator.startDelay = danmuItem.startOffset
            animator.start()
            playingAnimators[animatorListener] = animator
        }
    }

    override fun onDetachedFromWindow() {
        super.onDetachedFromWindow()
        stop()
        danmuItems.clear()
    }

    class DanmuItem(val text: CharSequence) {
        //在y方向的Top位置
        internal var y: Int = -1

        //在滚动
        internal var isAnimating = false

        //是否滚动过，滚动过一次就永远未true
        internal var animePlayed = false

        //[Mode.FIX]时指定左上位置
        var fixX = 0 //px
        var fixY = 0 //px

        var duration = 3000L //ms
        var startOffset: Long = Random.nextLong(500) //ms
    }

}

